﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ROOTFileSizeAnalyzer;
using System.Linq;
using System.Collections.Generic;
using System.Threading;

namespace TestROOTFileSizeAnalyzer
{
    [TestClass]
    public class TestROOTSizeParser
    {
        [TestMethod]
        public void TestCTor()
        {
            var bi = new ROOTSizeParser();
        }
        [TestMethod]
        public void TestEmptyString()
        {
            var bi = new ROOTSizeParser();
            var result = WaitForInput(bi.ParseInput(""));
            Assert.AreEqual(0, result.Length, "Expected null to come back");
        }

        /// <summary>
        /// Wait for input from the observable. We wait until it is totally done.
        /// </summary>
        /// <param name="iObservable"></param>
        /// <returns></returns>
        private ROOTBranchInfo[] WaitForInput(IObservable<ROOTBranchInfo> obs)
        {
            List<ROOTBranchInfo> results = new List<ROOTBranchInfo>();
            Exception theError = null;
            ManualResetEvent evt = new ManualResetEvent(false);
            var watcher = Observer.Create<ROOTBranchInfo>(
                nextValue =>
                {
                    results.Add(nextValue);
                },
                error =>
                {
                    theError = error;
                },
                () =>
                {
                    evt.Set();
                });

            obs.Subscribe(watcher);

            ///
            /// Wait till done
            /// 

            evt.WaitOne();

            if (theError != null)
            {
                throw theError;
            }

            return results.ToArray();
        }
        [TestMethod]
        public void TestBadString()
        {
            var bi = new ROOTSizeParser();
            var result = WaitForInput(bi.ParseInput("freak out mama!"));
            Assert.AreEqual(0, result.Length, "Expected null to come back");
        }

        [TestMethod]
        public void TestOneString()
        {
            string s = "*Br    1 :run       : run/i                                                  * \n*Entries :     4992 : Total  Size=      20506 bytes  File Size  =      20040 * \n*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.40     *";
            var bi = new ROOTSizeParser();
            var result = WaitForInput(bi.ParseInput(s));
            Assert.AreEqual(1, result.Length, "Expected 1 entry to come back");
            var r = result[0];
            TestCanonicalEntry(r);
        }

        [TestMethod]
        public void TestReallyLongType()
        {
            string s = "*Br   41 :trueparticledaughteridx :                                          *\n*         | trueparticledaughteridx[ntrueparticles][100]/I                   *\n*Entries :     4992 : Total  Size= 1345599104 bytes  File Size  = 1345498768 *\n*Baskets :     4992 : Basket Size=      32000 bytes  Compression=   1.00     *";
            var bi = new ROOTSizeParser();
            var result = WaitForInput(bi.ParseInput(s));
            Assert.AreEqual(1, result.Length, "Expected 1 entry to come back");
            var r = result[0];
            Assert.AreEqual(41, r.BranchNumber, "Expected 0 for the branch number");
            Assert.AreEqual("trueparticledaughteridx", r.BranchName, "bad branch name");
            Assert.AreEqual("trueparticledaughteridx[ntrueparticles][100]/I", r.BranchType, "bad branch type");
            Assert.AreEqual(4992, r.Entries, "bad number of entries");
            Assert.AreEqual(1345599104, r.TotalSize, "bad total size");
            Assert.AreEqual(1345498768, r.TotalSizeOnDisk, "bad file size");
            Assert.AreEqual(4992, r.NumberBaskets, "bad n baskets");
            Assert.AreEqual(32000, r.BasketSize, "bad basket size");
            Assert.AreEqual(1.0, r.CompressionFactor, "bad compression factor");

}

        [TestMethod]
        public void TestTwoEntries()
        {
            string s = "*Br    1 :run       : run/i                                                  * \n*Entries :     4992 : Total  Size=      20506 bytes  File Size  =      20040 * \n*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.40     *\n*Br    1 :run       : run/i                                                  * \n*Entries :     4992 : Total  Size=      20506 bytes  File Size  =      20040 * \n*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.40     *";
            var bi = new ROOTSizeParser();
            var result = WaitForInput(bi.ParseInput(s));
            Assert.AreEqual(2, result.Length, "Expected 1 entry to come back");
            TestCanonicalEntry(result[0]);
            TestCanonicalEntry(result[1]);
        }

        [TestMethod]
        public void TestWithROOTHeader()
        {
            string s = "******************************************************************************\n*Tree    :vtuple    : JetTagNtuple                                           *\n*Entries :     4992 : Total =      1718670851 bytes  File  Size = 1718350011 *\n*        :          : Tree compression factor =   1.00                       *\n******************************************************************************\n*Br    1 :run       : run/i                                                  * \n*Entries :     4992 : Total  Size=      20506 bytes  File Size  =      20040 * \n*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.40     *";
            var bi = new ROOTSizeParser();
            var result = WaitForInput(bi.ParseInput(s));
            Assert.AreEqual(1, result.Length, "Expected 1 entry to come back");
            TestCanonicalEntry(result[0]);
        }

        private static void TestCanonicalEntry(ROOTBranchInfo r)
        {
            Assert.AreEqual(1, r.BranchNumber, "Expected 0 for the branch number");
            Assert.AreEqual("run", r.BranchName, "bad branch name");
            Assert.AreEqual("run/i", r.BranchType, "bad branch type");
            Assert.AreEqual(4992, r.Entries, "bad number of entries");
            Assert.AreEqual(20506, r.TotalSize, "bad total size");
            Assert.AreEqual(20040, r.TotalSizeOnDisk, "bad file size");
            Assert.AreEqual(1, r.NumberBaskets, "bad n baskets");
            Assert.AreEqual(32000, r.BasketSize, "bad basket size");
            Assert.AreEqual(1.4, r.CompressionFactor, "bad compression factor");
        }
    }
}